/**
 * Copyright (C) 2018-2019
 * All rights reserved, Designed By www.joolun.com
 * 注意：
 * 本软件为www.joolun.com开发研制，项目使用请保留此说明
 */
package com.jjsj.web.api;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.jjsj.common.core.domain.AjaxResult;
import com.jjsj.common.utils.DateUtils;
import com.jjsj.mall.config.CommonConstants;
import com.jjsj.mall.config.MallConfigProperties;
import com.jjsj.mall.constant.MallConstants;
import com.jjsj.mall.dto.PlaceOrderDTO;
import com.jjsj.mall.entity.OrderInfo;
import com.jjsj.mall.entity.OrderLogistics;
import com.jjsj.mall.entity.OrderReceipt;
import com.jjsj.mall.enums.OrderInfoEnum;
import com.jjsj.mall.service.IOrderReceiptService;
import com.jjsj.mall.service.OrderInfoService;
import com.jjsj.mall.service.OrderLogisticsService;
import com.jjsj.mall.service.SwiftPayService;
import com.jjsj.mall.util.IpUtil;
import com.jjsj.mall.util.SignUtil;
import com.jjsj.mall.util.XmlUtils;
import com.jjsj.weixin.constant.MyReturnCode;
import com.jjsj.weixin.entity.WxUser;
import com.jjsj.weixin.utils.ThirdSessionHolder;
import com.jjsj.weixin.utils.WxMaUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * 商城订单
 *
 * @author JL
 * @date 2019-09-10 15:21:22
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/weixin/api/ma/orderinfo")
@Api(value = "orderinfo", tags = "商城订单API")
public class OrderInfoApi {

    private final OrderInfoService orderInfoService;
    private final MallConfigProperties mallConfigProperties;
    private final OrderLogisticsService orderLogisticsService;
    private final IOrderReceiptService orderReceiptService;

    /**
     * 分页查询
     *
     * @param page      分页对象
     * @param orderInfo 商城订单
     * @return
     */
    @ApiOperation(value = "分页查询")
    @GetMapping("/page")
    public AjaxResult getOrderInfoPage(Page page, OrderInfo orderInfo) {
        orderInfo.setUserId(ThirdSessionHolder.getWxUserId());
        return AjaxResult.success(orderInfoService.page2(page, orderInfo));
    }

    /**
     * 通过id查询商城订单
     *
     * @param id
     * @return R
     */
    @ApiOperation(value = "通过id查询商城订单")
    @GetMapping("/{id}")
    public AjaxResult getById(HttpServletRequest request, @PathVariable("id") String id) {
        OrderInfo orderInfo = orderInfoService.getById2(id);
        OrderLogistics orderLogistics = orderLogisticsService.getById(orderInfo.getLogisticsId());
        OrderReceipt orderReceipt = orderReceiptService.getById(orderInfo.getReceiptId());
        orderInfo.setOrderLogistics(orderLogistics);
        orderInfo.setOrderReceipt(orderReceipt);
        return AjaxResult.success(orderInfo);
    }

    /**
     * 新增商城订单
     *
     * @param placeOrderDTO 商城订单
     * @return R
     */
    @ApiOperation(value = "新增商城订单")
    @PostMapping
    public AjaxResult save(@RequestBody PlaceOrderDTO placeOrderDTO) {
        placeOrderDTO.setUserId(ThirdSessionHolder.getWxUserId());
        placeOrderDTO.setPaymentWay(MallConstants.PAYMENT_WAY_2);
        OrderInfo orderInfo = orderInfoService.orderSub(placeOrderDTO);
        if (orderInfo == null) {
            return AjaxResult.error(MyReturnCode.ERR_70003.getCode(), MyReturnCode.ERR_70003.getMsg());
        }
        return AjaxResult.success(orderInfo);
    }

    /**
     * 通过id删除商城订单
     *
     * @param id
     * @return R
     */
    @ApiOperation(value = "通过id删除商城订单")
    @DeleteMapping("/{id}")
    public AjaxResult removeById(@PathVariable String id) {
        OrderInfo orderInfo = orderInfoService.getById(id);
        if (orderInfo == null) {
            return AjaxResult.error(MyReturnCode.ERR_70005.getCode(), MyReturnCode.ERR_70005.getMsg());
        }
        if (!OrderInfoEnum.STATUS_5.getValue().equals(orderInfo.getStatus()) || CommonConstants.YES.equals(orderInfo.getIsPay())) {
            return AjaxResult.error(MyReturnCode.ERR_70001.getCode(), MyReturnCode.ERR_70001.getMsg());
        }
        return AjaxResult.success(orderInfoService.removeById(id));
    }

    /**
     * 取消商城订单
     *
     * @param id 商城订单
     * @return R
     */
    @ApiOperation(value = "取消商城订单")
    @PutMapping("/cancel/{id}")
    public AjaxResult orderCancel(@PathVariable String id) {
        OrderInfo orderInfo = orderInfoService.getById(id);
        if (orderInfo == null) {
            return AjaxResult.error(MyReturnCode.ERR_70005.getCode(), MyReturnCode.ERR_70005.getMsg());
        }
        if (!CommonConstants.NO.equals(orderInfo.getIsPay())) {//只有未支付订单能取消
            return AjaxResult.error(MyReturnCode.ERR_70001.getCode(), MyReturnCode.ERR_70001.getMsg());
        }
        orderInfoService.orderCancel(orderInfo);
        return AjaxResult.success();
    }

    /**
     * 商城订单确认收货
     *
     * @param id 商城订单
     * @return R
     */
    @ApiOperation(value = "商城订单确认收货")
    @PutMapping("/receive/{id}")
    public AjaxResult orderReceive(@PathVariable String id) {
        OrderInfo orderInfo = orderInfoService.getById(id);
        if (orderInfo == null) {
            return AjaxResult.error(MyReturnCode.ERR_70005.getCode(), MyReturnCode.ERR_70005.getMsg());
        }
        if (!OrderInfoEnum.STATUS_2.getValue().equals(orderInfo.getStatus())) {//只有待收货订单能确认收货
            return AjaxResult.error(MyReturnCode.ERR_70001.getCode(), MyReturnCode.ERR_70001.getMsg());
        }
        orderInfoService.orderReceive(orderInfo);
        return AjaxResult.success();
    }

    /**
     * 调用统一下单接口，并组装生成支付所需参数对象.
     *
     * @param orderInfo 统一下单请求参数
     * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
     */
    @ApiOperation(value = "调用统一下单接口")
    @PostMapping("/unifiedOrder")
    public AjaxResult unifiedOrder(HttpServletRequest request, @RequestBody OrderInfo orderInfo) throws WxPayException, IOException {
        //检验用户session登录
        WxUser wxUser = new WxUser();
        wxUser.setId(ThirdSessionHolder.getThirdSession().getWxUserId());
        wxUser.setSessionKey(ThirdSessionHolder.getThirdSession().getSessionKey());
        wxUser.setOpenId(ThirdSessionHolder.getThirdSession().getOpenId());
        orderInfo = orderInfoService.getById(orderInfo.getId());
        if (orderInfo == null) {
            return AjaxResult.error(MyReturnCode.ERR_70005.getCode(), MyReturnCode.ERR_70005.getMsg());
        }
        if (!CommonConstants.NO.equals(orderInfo.getIsPay())) {//只有未支付的详单能发起支付
            return AjaxResult.error(MyReturnCode.ERR_70004.getCode(), MyReturnCode.ERR_70004.getMsg());
        }
        if (orderInfo.getPaymentPrice().compareTo(BigDecimal.ZERO) == 0) {//0元购买不调支付
            orderInfo.setPaymentTime(LocalDateTime.now());
            orderInfoService.notifyOrder(orderInfo);
            return AjaxResult.success();
        }
        String appId = WxMaUtil.getAppId(request);
        String ip = IpUtil.getIpAddr(request);
//        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
//        wxPayUnifiedOrderRequest.setAppid(appId);
//        String body = orderInfo.getName();
//        body = body.length() > 40 ? body.substring(0, 39) : body;
//        wxPayUnifiedOrderRequest.setBody(body);
//        wxPayUnifiedOrderRequest.setOutTradeNo(orderInfo.getOrderNo());
//        wxPayUnifiedOrderRequest.setTotalFee(orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue());
//        wxPayUnifiedOrderRequest.setTradeType("JSAPI");
//        wxPayUnifiedOrderRequest.setNotifyUrl(mallConfigProperties.getNotifyHost() + "/weixin/api/ma/orderinfo/notify-order");
//        wxPayUnifiedOrderRequest.setSpbillCreateIp("127.0.0.1");
//        wxPayUnifiedOrderRequest.setOpenid(wxUser.getOpenId());
//        WxPayService wxPayService = WxPayConfiguration.getPayService();
//        return AjaxResult.success(JSONUtil.parse(wxPayService.createOrder(wxPayUnifiedOrderRequest)));
        SwiftPayService swiftPayService = new SwiftPayService();
        return AjaxResult.success(swiftPayService.pay(wxUser, orderInfo, appId, ip));
    }

    /**
     * 支付回调
     *
     * @param req
     * @return
     * @throws WxPayException
     */
    @ApiOperation(value = "支付回调")
    @PostMapping("/notify-order")
    public void notifyOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            log.debug("收到通知...");
            req.setCharacterEncoding("utf-8");
            resp.setCharacterEncoding("utf-8");
            resp.setHeader("Content-type", "text/html;charset=UTF-8");

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            String FEATURE = null;
            try {
                FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
                dbf.setFeature(FEATURE, true);
                FEATURE = "http://xml.org/sax/features/external-general-entities";
                dbf.setFeature(FEATURE, false);
                FEATURE = "http://xml.org/sax/features/external-parameter-entities";
                dbf.setFeature(FEATURE, false);
                FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
                dbf.setFeature(FEATURE, false);
                dbf.setXIncludeAware(false);
                dbf.setExpandEntityReferences(false);
            } catch (ParserConfigurationException e) {
                // This should catch a failed setFeature feature
                System.out.println("ParserConfigurationException was thrown. The feature '" +
                        FEATURE + "' is probably not supported by your XML processor.");
            }
            String resString = XmlUtils.parseRequst(req);
            log.debug("请求的内容：" + resString);
            String respString = "error";
            if (resString != null && !"".equals(resString)) {
                Map<String, String> map = XmlUtils.toMap(resString.getBytes(), "utf-8");
                String res = XmlUtils.toXml(map);
                String sign_type = map.get("sign_type");
                String reSign = map.get("sign");
                System.out.println("通知内容：" + res);
                log.debug("请求结果：" + res);
                if (map.containsKey("sign")) {
                    if (!SignUtil.verifySign(reSign, sign_type, map)) {
                        res = "验证签名不通过";
                        respString = "error";
                    } else {
                        String status = map.get("status");
                        if (status != null && "0".equals(status)) {
                            String result_code = map.get("result_code");
                            if (result_code != null && "0".equals(result_code)) {
                                OrderInfo orderInfo = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
                                        .eq(OrderInfo::getOrderNo, map.get("out_trade_no")));
                                if (orderInfo != null) {
                                    if (orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == Integer.parseInt(map.get("total_fee"))) {
                                        String timeEnd = map.get("time_end");
//                                        LocalDateTime paymentTime = LocalDateTime.parse(timeEnd);
                                        LocalDateTime paymentTime = DateUtils.parseStringToLocalDateTime(timeEnd, DateUtils.YYYYMMDDHHMMSS);
                                        orderInfo.setPaymentTime(paymentTime);
                                        orderInfo.setTransactionId(map.get("transaction_id"));
                                        orderInfoService.notifyOrder(orderInfo);
                                        respString = "success";
                                    } else {
                                        respString = "error";
                                    }
                                } else {
                                    respString = "error";
                                }
                            }
                        }
                    }
                }
            }
            resp.getWriter().write(respString);
        } catch (Exception e) {
            log.error("操作失败，原因：", e);
        }
    }
//    public String notifyOrder(@RequestBody String xmlData) throws WxPayException {
//        log.info("支付回调:" + xmlData);
//        WxPayService wxPayService = WxPayConfiguration.getPayService();
//        WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
//        OrderInfo orderInfo = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
//                .eq(OrderInfo::getOrderNo, notifyResult.getOutTradeNo()));
//        if (orderInfo != null) {
//            if (orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == notifyResult.getTotalFee()) {
//                String timeEnd = notifyResult.getTimeEnd();
//                LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
//                orderInfo.setPaymentTime(paymentTime);
//                orderInfo.setTransactionId(notifyResult.getTransactionId());
//                orderInfoService.notifyOrder(orderInfo);
//                return WxPayNotifyResponse.success("成功");
//            } else {
//                return WxPayNotifyResponse.fail("付款金额与订单金额不等");
//            }
//        } else {
//            return WxPayNotifyResponse.fail("无此订单");
//        }
//    }

    /**
     * 物流信息回调
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "物流信息回调")
    @PostMapping("/notify-logisticsr")
    public String notifyLogisticsr(HttpServletRequest request, HttpServletResponse response) {
        String param = request.getParameter("param");
        String logisticsId = request.getParameter("logisticsId");
        String tenantId = request.getParameter("tenantId");
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("result", false);
        map.put("returnCode", "500");
        map.put("message", "保存失败");
        try {
            JSONObject jsonObject = JSONUtil.parseObj(param);
//			orderInfoService.notifyLogisticsr(logisticsId, jsonObject);
            map.put("result", true);
            map.put("returnCode", "200");
            map.put("message", "保存成功");
            //这里必须返回，否则认为失败，过30分钟又会重复推送。
            response.getWriter().print(JSONUtil.parseObj(map));
        } catch (Exception e) {
            map.put("message", "保存失败" + e.getMessage());
            //保存失败，服务端等30分钟会重复推送。
            try {
                response.getWriter().print(JSONUtil.parseObj(map));
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 统计各个状态订单计数
     *
     * @param orderInfo
     * @return R
     */
    @ApiOperation(value = "统计各个状态订单计数")
    @GetMapping("/countAll")
    public AjaxResult count(OrderInfo orderInfo) {
        orderInfo.setUserId(ThirdSessionHolder.getWxUserId());
        Collection<String> collection = new HashSet<>();
        collection.add("1");
        collection.add("2");
        collection.add("3");
        Map<String, Integer> countAll = new HashMap<>();
        countAll.put(OrderInfoEnum.STATUS_0.getValue(), orderInfoService.count(Wrappers.query(orderInfo).lambda()
                .isNull(OrderInfo::getStatus)
                .eq(OrderInfo::getIsPay, CommonConstants.NO)));

        countAll.put(OrderInfoEnum.STATUS_1.getValue(), orderInfoService.count(Wrappers.query(orderInfo).lambda()
                .eq(OrderInfo::getStatus, OrderInfoEnum.STATUS_1.getValue())
                .eq(OrderInfo::getIsPay, CommonConstants.YES)));

        countAll.put(OrderInfoEnum.STATUS_2.getValue(), orderInfoService.count(Wrappers.query(orderInfo).lambda()
                .eq(OrderInfo::getStatus, OrderInfoEnum.STATUS_2.getValue())
                .eq(OrderInfo::getIsPay, CommonConstants.YES)));

        countAll.put(OrderInfoEnum.STATUS_3.getValue(), orderInfoService.count(Wrappers.query(orderInfo).lambda()
                .eq(OrderInfo::getStatus, OrderInfoEnum.STATUS_3.getValue())
                .eq(OrderInfo::getIsPay, CommonConstants.YES)));
        return AjaxResult.success(countAll);
    }
}
